home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 May: Tool Chest / Developer CD Series May 1996 (Tool Chest) (Apple Computer) (1996).iso / Sample Code / Snippets / Printing / PDlog Expand / PDlog Expand.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-06-21  |  12.9 KB  |  420 lines  |  [TEXT/KAHL]

  1. /* PDlog Expand.c    Derived from TN #95.
  2.  
  3. Dave Hersey, Apple Developer Technical Support.
  4.  
  5.   10/9/91…    v1.0
  6.   2/25/92…  v1.0.1 --> fixed lack of print handle tossing and added something to print.       <dmh>
  7.   9/29/93…  v1.0.2 --> fixed bug in Append_DITL (also in TN #95) which appends 2 extra bytes. <dmh>
  8.   6/20/95…    v1.0.3 --> updated for Universal Headers and MWC-PPC                              <njvt>
  9.  
  10.    NOTE: Apple reserves the top half of the screen (where the current DITL
  11.    items are located). Applications may use the bottom half of the screen to
  12.    add items, but should not change any items in the top half of the screen.
  13.    An application should expand the print dialogs only as much as is
  14.    absolutely necessary.
  15.  
  16.    A global search and replace of 'Job' with 'Stl' will produce code that
  17.    modifies the style dialog.
  18.    
  19.  
  20. */
  21.  
  22. #include <Printing.h>
  23. #include <MixedMode.h>
  24.  
  25. static TPPrDlg PrtJobDialog;        /* pointer to job dialog */
  26.  
  27. /* 
  28.  
  29. This points to the following structure:
  30.     
  31. struct TPrDlg {
  32.     DialogRecord                    Dlg;                        // The Dialog window
  33.     ModalFilterUPP                    pFltrProc;                    // The Filter Proc.
  34.     PItemUPP                        pItemProc;                    // The Item evaluating proc.
  35.     THPrint                            hPrintUsr;                    // The user's print record.
  36.     Boolean                            fDoIt;
  37.     Boolean                            fDone;
  38.     long                            lUser1;                        // Four longs for apps to hang global data.
  39.     long                            lUser2;                        // Plus more stuff needed by the particular
  40.     long                            lUser3;                        // printing dialog.
  41.     long                            lUser4;
  42. };
  43. typedef struct TPrDlg TPrDlg;
  44. typedef TPrDlg *TPPrDlg;
  45. typedef TPPrDlg TPPrDlgRef;
  46.  
  47. */
  48.  
  49. /* Declare ‘pascal’ functions and procedures */
  50.  
  51. extern short        Append_DITL(TPPrDlg, short);            /* Our AppendDITL function.            */
  52. extern pascal    TPPrDlg MyJobDlgInit(THPrint);        /* Our extention to PrJobInit.        */
  53. extern pascal    void MyJobItems(TPPrDlg, short);    /* Our modal item handler.            */
  54. extern OSErr    Print(void);
  55.  
  56. #define MyDITL 256  /* resource ID of my DITL to be spliced onto job dialog */
  57.  
  58. THPrint hPrintRec;          /* handle to print record */
  59. long prFirstItem;           /* save our first item here */
  60. long prPItemProc;           /* we need to store the old itemProc here */
  61.  
  62. /*-----------------------------------------------------------------------*/
  63.     WindowPtr   MyWindow;
  64.     OSErr       err;
  65.     Str255      myStr;
  66.  
  67. #if PRAGMA_ALIGN_SUPPORTED
  68. #pragma options align=mac68k
  69. #endif
  70.  
  71. typedef
  72.     struct dialog_item_struct
  73.     {
  74.         Handle  handle;     /* handle or procedure pointer for this item */
  75.         Rect    bounds;     /* display rectangle for this item */
  76.         char    type;       /* item type - 1 */
  77.         char    data[1];    /* length byte of data */
  78.     }
  79.     DialogItem, *DialogItemPtr, **DialogItemHandle;
  80.  
  81. typedef
  82.     struct append_item_list_struct
  83.     {
  84.         short         max_index; /* number of items - 1 */
  85.         DialogItem    items[1]; /* first item in the array */
  86.     }
  87.     ItemList, *ItemListPtr, **ItemListHandle;
  88.  
  89. typedef
  90.     union signed_byte_union
  91.     {
  92.         short   integer;
  93.         char    bytes[2];
  94.     }
  95.     ByteAccess;
  96.  
  97.  
  98. /*    This routine appends all of the items of a specified DITL    */
  99. /*    onto the end of a specified DLOG — We don’t even need to know the format    */
  100. /*    of the DLOG    */
  101.  
  102. /*    this will be done in 3 steps:    */
  103. /*     1. append the items of the specified DITL onto the existing DLOG    */
  104. /*     2. expand the original dialog window as required    */
  105. /*     3. return the adjusted number of the first new user item    */
  106.  
  107.  
  108. short Append_DITL(TPPrDlg dialog, short item_list_ID)
  109. {
  110.     Point             offset;
  111.     Rect            max_rect;
  112.     ItemListHandle     append_item_list;    /* handle to DITL being appended */
  113.     DialogItemPtr     item;                /* pointer to item being appended */
  114.     ItemListHandle    dlg_item_list;        /* handle to DLOG's item list */
  115.     short           first_item;
  116.     short           new_items, data_size, i;
  117.     ByteAccess        usb;
  118.     OSErr              err;
  119.  
  120. /*
  121.     Using the original DLOG
  122.  
  123.     1. Remember the original window Size.
  124.     2. Set the offset Point to be the bottom of the original window.
  125.     3. Subtract 5 pixels from bottom and right, to be added
  126.        back later after we have possibly expanded window.
  127.     4. Get working Handle to original item list.
  128.     5. Calculate our first item number to be returned to caller.
  129.     6. Get locked Handle to DITL to be appended.
  130.     7. Calculate count of new items.
  131. */
  132.  
  133.     if (dialog == NULL) ExitToShell();
  134.  
  135.     max_rect = ((DialogPeek)dialog)->window.port.portRect;
  136.     offset.v = max_rect.bottom;
  137.     offset.h = 0;
  138.     max_rect.bottom -= 5;
  139.     max_rect.right -= 5;
  140.  
  141.     dlg_item_list = (ItemListHandle)((DialogPeek)dialog)->items;
  142.     first_item = (**dlg_item_list).max_index + 2;
  143.  
  144.     append_item_list = (ItemListHandle)GetResource('DITL', item_list_ID);
  145.     if ( append_item_list == NULL )
  146.         return first_item;
  147.  
  148.     HLock((Handle)append_item_list);
  149.     new_items = (**append_item_list).max_index + 1;
  150.  
  151. /*
  152.      For each item,
  153.       1. Offset the rectangle to follow the original window.
  154.       2. Make the original window larger if necessary.
  155.       3. fill in item handle according to type.
  156. */
  157.  
  158.     item = (**append_item_list).items;
  159.     for ( i = 0; i < new_items; i++ )
  160.     {
  161.         OffsetRect(&item->bounds, offset.h, offset.v);
  162.         UnionRect(&item->bounds, &max_rect, &max_rect);
  163.         usb.integer = 0;
  164.         usb.bytes[1] = item->data[0];
  165.  
  166.         switch ( item->type & 0x7F )
  167.         {
  168.             case ctrlItem + btnCtrl :
  169.             case ctrlItem + chkCtrl :
  170.             case ctrlItem + radCtrl :
  171.                 item->handle = (Handle)NewControl((DialogPtr) dialog,
  172.                                                   &item->bounds,
  173.                                                   (StringPtr)item->data,
  174.                                                   TRUE,
  175.                                                   0, 0, 1,
  176.                                                   item->type & 0x03,
  177.                                                   0);
  178.             break;
  179.  
  180.             case ctrlItem + resCtrl :
  181.             {
  182.                 item->handle = (Handle)GetNewControl(*(short*)(item->data + 1), (DialogPtr) dialog);
  183.                 (**(ControlHandle)item->handle).contrlRect = item->bounds;
  184.             }
  185.             break;
  186.  
  187.             case statText :
  188.             case editText :
  189.                 err = PtrToHand(item->data + 1, &item->handle, usb.integer);
  190.             break;
  191.  
  192.             case iconItem :
  193.                 item->handle = GetIcon(*(short*)(item->data + 1));
  194.             break;
  195.  
  196.             case picItem :
  197.                 item->handle = (Handle)GetPicture(*(short*)(item->data + 1));
  198.             break;
  199.  
  200.             default :
  201.                 item->handle = NULL;
  202.         }
  203.  
  204.         data_size = (usb.integer + 1) & 0xFFFE;
  205.         item = (DialogItemPtr)((char*)item + data_size + sizeof(DialogItem));
  206.     }
  207.  
  208.  // We need to subtract the short below because otherwise the size of the DITL count
  209.  // gets factored in twice, and the resulting DTIL has two bytes of garbage appended
  210.  // to it.  This is a problem with the original TN#95 code as well.
  211.  
  212.     err = PtrAndHand((**append_item_list).items,
  213.                      (Handle)dlg_item_list,
  214.                      GetHandleSize((Handle) append_item_list)
  215.                      - sizeof(short));
  216.  
  217.     (**dlg_item_list).max_index += new_items;
  218.     HUnlock((Handle) append_item_list);
  219.     ReleaseResource((Handle) append_item_list);
  220.  
  221.     max_rect.bottom += 5;
  222.     max_rect.right += 5;
  223.     SizeWindow((WindowPtr) dialog, max_rect.right, max_rect.bottom, TRUE);
  224.  
  225.     return first_item;
  226. }
  227.  
  228.  
  229. /*------------------------------------------------------------------------*/
  230.  
  231. OSErr Print()
  232. {
  233.     TPPrPort    pPrPort;
  234.     Rect        aRect;
  235.     TPrStatus    theStatus;
  236.     
  237.     
  238.     /* call PrJobInit to get pointer to the invisible job dialog */
  239.     hPrintRec = (THPrint)(NewHandle(sizeof(TPrint)));
  240.     PrintDefault(hPrintRec);
  241.     PrValidate(hPrintRec);
  242.     if (PrError() != noErr)
  243.         return PrError();        
  244.  
  245.     PrtJobDialog = PrJobInit(hPrintRec);
  246.        
  247.     if (PrError() != noErr)
  248.         return PrError();        
  249.  
  250.     if (!PrDlgMain(hPrintRec, NewPDlgInitProc(MyJobDlgInit))) /* this line does all the stuff */
  251.         return iPrAbort;
  252.  
  253.     if (PrError() != noErr)
  254.         return PrError();        
  255.  
  256.     pPrPort = PrOpenDoc(hPrintRec, NULL, NULL);
  257.     PrOpenPage(pPrPort, NULL);
  258.     
  259.     aRect = (*hPrintRec)->prInfo.rPage;
  260.     InsetRect(&aRect, 20, 20);
  261.     PenSize(4, 4);
  262.     FrameRect(&aRect);
  263.     
  264.     PrClosePage(pPrPort);
  265.     PrCloseDoc(pPrPort);
  266.  
  267.     if (!PrError() && (*hPrintRec)->prJob.bJDocLoop == bSpoolLoop)
  268.         PrPicFile(hPrintRec, NULL, NULL, NULL, &theStatus);
  269.  
  270.  
  271. /* that's all for now */
  272.         
  273.     if (hPrintRec) DisposeHandle((Handle) hPrintRec);
  274.         
  275. } /* Print */
  276.  
  277. /*------------------------------------------------------------------------*/
  278.  
  279. pascal TPPrDlg MyJobDlgInit (hPrint)
  280. THPrint hPrint;
  281. /*
  282.    this routine appends items to the standard job dialog and sets up the
  283.    user fields of the printing dialog record TPRDlg
  284.  
  285.    This routine will be called by PrDlgMain
  286. */
  287.  
  288. {
  289.     short      firstItem;    /* first new item number */
  290.     
  291.     short      itemType, item;
  292.     Handle     itemH;
  293.     Rect       itemBox;
  294.     
  295.     firstItem = Append_DITL(PrtJobDialog, MyDITL); /*call routine to do this */
  296.     
  297.     prFirstItem = firstItem; /* save this so MyJobItems can find it */
  298.  
  299. /* now we'll set up our DITL items -- The radio buttons */
  300.     
  301.     for (item = 5; item <= 7; item++)
  302.     {
  303.         GetDItem((DialogPtr) PrtJobDialog,firstItem + item -1,&itemType,&itemH,&itemBox);
  304.         SetCtlValue((ControlHandle) itemH, (item == 5));
  305.     }
  306.     
  307. /* now we'll set up the second of our DITL items  -- The checkbox */
  308.  
  309.     GetDItem((DialogPtr) PrtJobDialog,firstItem +2,&itemType,&itemH,&itemBox);
  310.     SetCtlValue((ControlHandle) itemH,1);
  311.  
  312. /*
  313.    Now comes the part where we patch in our item handler.  We have to save
  314.    the old item handler address, so we can call it if one of the standard
  315.    items is hit, and put our item handler's address in pItemProc field of
  316.    the TPrDlg struct
  317. */
  318.  
  319.     prPItemProc = (long)PrtJobDialog->pItemProc;
  320.     
  321. /* Now we'll tell the modal item handler where our routine is */
  322.     PrtJobDialog->pItemProc = NewPItemProc(MyJobItems) ;
  323.     
  324.  
  325. /* PrDlgMain expects a pointer to the modified dialog to be returned...*/
  326.     return PrtJobDialog;
  327.     
  328. } /*myJobDlgInit*/
  329.  
  330. /*-----------------------------------------------------------------------*/
  331.  
  332. /* here's the analogue to the SF dialog hook */
  333.  
  334. pascal void MyJobItems( TPPrDlg theDialog, short itemNo )
  335. { /* MyJobItems */
  336.     short   myItem;
  337.     short   firstItem, item, itemType, theValue;
  338.     Handle  itemH;
  339.     Rect    itemBox;
  340.     
  341.     firstItem = prFirstItem;      /* remember, we saved this in myJobDlgInit */
  342.     myItem = itemNo-firstItem+1;  /* "localize" current item No */
  343.     if (myItem > 0)               /* if localized item > 0, it's one of ours */
  344.     {
  345.         /* find out which of our items was hit */
  346.  
  347.         switch (myItem)
  348.         {
  349.             case 1:            /*    Static text.    */
  350.                 break;
  351.             case 2:            /*    Edit text.        */
  352.                 break;
  353.             case 3:            /*    Check box.        */
  354.                        GetDItem((DialogPtr) theDialog,firstItem +2,&itemType,&itemH,&itemBox);
  355.                      theValue = GetCtlValue((ControlHandle) itemH);
  356.                      SetCtlValue((ControlHandle) itemH, theValue != 1);
  357.                 break;
  358.             case 4:            /*    Push button.    */
  359.                 break;
  360.             case 5:            /*    Radio buttons    */
  361.             case 6:
  362.             case 7:
  363.                    for (item = 5; item <= 7; item++)
  364.                    {
  365.                        GetDItem((DialogPtr) theDialog,firstItem +item -1,&itemType,&itemH,&itemBox);
  366.                      SetCtlValue((ControlHandle) itemH, item == myItem);
  367.                    }
  368.                 break;
  369.             case 8:            /*    Edit text.        */
  370.                 break;
  371.             default: Debugger(); /* OH OH */    
  372.         } /* switch */
  373.     } /* if (myItem > 0) */
  374.     else /* chain to standard item handler, whose address is saved in 
  375.               prPItemProc */
  376.     {
  377.     
  378. #if CFMSYSTEMCALLS
  379.         
  380.         // under ppc we need to create a proc info structure, this tells us 
  381.         // what the arguments are and how they get passed on the stack
  382.         enum {
  383.             uppPItemProcInfo = kPascalStackBased
  384.                  | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(DialogPtr)))
  385.                  | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(short)))
  386.         };
  387.  
  388.         // call the proc ptr we sut up in prPItemProc earlier
  389.         CallUniversalProc((UniversalProcPtr) prPItemProc, uppPItemProcInfo, theDialog, itemNo) ;
  390.         
  391. #else
  392.  
  393.         // for the 68k case use this.  This code sucks, but it works...
  394.         // call the standard item handler.
  395.         ((pascal void (*) (TPPrDlg, short)) (Ptr) prPItemProc) (theDialog, itemNo);
  396.         
  397. #endif
  398.     }
  399. } /* MyJobItems */
  400.  
  401.  
  402. main()
  403. {    
  404.     Rect        myWRect;
  405.     
  406.     InitGraf(&qd.thePort);
  407.     InitFonts();
  408.     InitWindows();
  409.     InitMenus();
  410.     InitDialogs((long)nil);
  411.     InitCursor();
  412.     SetRect(&myWRect,50,260,350,340);
  413.     
  414.     /* call the routine that does printing */
  415.     PrOpen();
  416.     err = Print();
  417.     
  418.     PrClose();
  419. } /* main */
  420.